Add light mode theme toggle#46
Conversation
Promote main to production
Extract infrastructure metadata from AgnosticD v2 CRDs during
catalog refresh for Publishing House express mode queries.
- Alembic migration 002: new columns on catalog_items (is_agd_v2,
agd_config, cloud_provider, ocp_version, os_image, instances_json,
sizing), 4 new tables (catalog_item_workloads, workload_mapping,
workload_aliases, catalog_item_acl_groups)
- V2 detection via exact scm_url match, FQCN workload parsing
- Handles both OCP items (flat workloads list) and RHEL/VM items
(dict-based software_workloads + instances + os_image)
- 35 verified workload mappings + 25 product aliases in seed file
- CLI: rcars infra stats, rcars workload {sync,unmapped,map,alias,list}
- GET /catalog/{ci_name} enriched with workloads + ACL groups
- Design spec at docs/superpowers/specs/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The CLI refresh path had the same upsert loop as the worker but was missing the _workloads/_acl_groups pop-and-sync step added to ops.py. Without this, CLI-triggered refreshes populated the infra columns but not the junction tables. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
alembic/ and alembic.ini were at the repo root but the API container build uses contextDir=src/api, so migrations were never available in the container image. Moved both into src/api/ where they ship with the app via COPY . . in the Containerfile. Updated Ansible --tags migrate to run rcars init-db (CREATE TABLE IF NOT EXISTS for new installs) then alembic upgrade head (ALTER TABLE for existing schemas). This makes schema changes deployable to production without dropping the database. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Alembic was moved from repo root to src/api/ so it ships in the container image. Updated all documentation to reflect the new location and the Ansible migrate workflow (rcars init-db + alembic upgrade head). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Alembic's context.configure() requires a SQLAlchemy connection, not a raw psycopg3 connection. Use create_engine() with postgresql+psycopg dialect (psycopg3) instead of psycopg.connect() directly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… (Session 2) API endpoints: - GET /catalog/search/infrastructure — faceted search by workloads, config, cloud_provider, ocp_version, os_image (alias resolution) - GET /catalog/facets — available filter values with counts - GET/POST/DELETE /catalog/workload-mappings — mapping CRUD - GET /catalog/infra-stats — v2/workload coverage stats - POST /admin/scan-workloads — trigger workload repo scan Workload scanner (services/workload_scanner.py): - Clones agDv2 collection repos from github.com/agnosticd/* - Reads role code (defaults, tasks, templates) for each role - LLM analysis via Haiku to determine product/description/category - SHA-based change detection via ls-remote (skip unchanged repos) - Upserts verified mappings, skips infrastructure plumbing roles Pipeline integration: - run_workload_scan() worker function (ops.py) - Step 4 in nightly maintenance pipeline (gated on workload_scan_enabled) - Registered in WorkerSettings with 1hr timeout - CLI: rcars workload scan [--collection X] [--force] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New docs/architecture/schema-reference.md with full column-level details for all 14 tables (including 5 new infra tables) - system-design.md: replaced inline table descriptions with summary table + link to reference. Added Infrastructure Metadata Extraction section covering v2 detection, workload scanning, faceted search. Restored full vector embeddings explanation. - CLAUDE.md: updated schema table (14 tables), API endpoints (35), CLI commands (infra + workload groups), nightly pipeline (4 steps) - cli-guide.md: added rcars infra and rcars workload command docs with examples and explanations - operations.md: updated pipeline from 3 to 4 steps, added workload scan change detection explanation, RCARS_WORKLOAD_SCAN_ENABLED var - mkdocs.yml: added Schema Reference to nav - Fixed .gitignore: /OPERATIONS.md scoped to root only Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Browse page: - [v2] badge on AgnosticD v2 item headers - Infrastructure detail panel in expanded items: config type, cloud provider, OCP version, OS image, workloads list, ACL groups - "v2" filter toggle to show only AgnosticD v2 items Admin page: - "Workload Repos" section with Scan button (job polling + log) - Infrastructure stats in Catalog Status table: v2 items, workloads coverage, mapped/verified/unmapped role counts API client: - 8 new methods for infrastructure search, facets, workload mappings, infra stats, and workload scanning - Extended CatalogItem/ItemDetail interfaces with v2 infra fields Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Infrastructure-aware catalog metadata marked complete (deployed to dev). Remaining UI items (filter dropdowns, mapping management table, combined query) moved to separate backlog section. Full session handoff notes in WORKLOG.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removes [esbuild](https://github.com/evanw/esbuild). It's no longer used after updating ancestor dependencies [esbuild](https://github.com/evanw/esbuild), [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) and [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). These dependencies need to be updated together. Removes `esbuild` Updates `@vitejs/plugin-react` from 4.7.0 to 6.0.2 - [Release notes](https://github.com/vitejs/vite-plugin-react/releases) - [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.0.2/packages/plugin-react) Updates `vite` from 6.4.2 to 8.0.16 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.0.16/packages/vite) --- updated-dependencies: - dependency-name: esbuild dependency-version: dependency-type: indirect - dependency-name: "@vitejs/plugin-react" dependency-version: 6.0.2 dependency-type: direct:development - dependency-name: vite dependency-version: 8.0.16 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com>
- Design spec for Browse page filter system overhaul: collapsible filter panel with Cloud Provider, Workloads (multi-select), and AgnosticD Config dropdowns; server-side filtering replacing client-side; numbered pagination; role-based curator filter separation - Backlog item for future contextual sidebar navigation redesign Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8 tasks: backend filtered query, route params, API client, pagination component, workload multi-select, BrowsePage rewrite, admin deep links, manual testing checklist. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… filters Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ilter params Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update listCatalog API client with search/stage/infra/content_filter params - Add Pagination component with numbered pages and ellipsis - Add WorkloadMultiSelect dropdown with checkboxes - Add CSS for filter panel, curator panel, pagination, and multi-select Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…gination - Replace client-side load-all with server-side filtered queries - Collapsible filter panel: Cloud Provider, Workloads (multi-select), AgnosticD Config dropdowns with dismissable filter chips - Curator-only filter panel (amber): Unanalyzed, Failures, Stale, Needs Review - Numbered pagination replacing prev/next buttons - URL state sync for shareable filtered views - Debounced search (300ms) - Update Admin deep links from ?filter= to ?content_filter= Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace monolithic Catalog Status table with 3 stat cards (Catalog, Analysis, Infrastructure) in responsive grid - Add Workload Mapping Management section with mapped/unmapped tables, inline Map form, and delete capability - Reorder sections: Status cards at top, operations grouped, workload scan and mappings at bottom - Flexible-width layout scaling with browser window Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three tabs: Status (stat cards + scheduled maintenance), Sync & Analysis (catalog sync + content analysis + full re-analysis), Workloads (workload scan + mapping management). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…step Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move recent jobs table into Sync & Analysis as a collapsible section. Remove Workers from sidebar navigation. Old /admin/workers URL redirects to /admin/catalog. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Browse page redesign and admin reorganization complete. Combined query deferred with rationale. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cost per provision is a curator/platform metric, not useful for content selection. A field seller picking labs for a conference doesn't need to know that a lab costs $300 to provision — and the number without context is confusing. The metric is still on the retirement dashboard where it belongs. Also renamed "provisions" to "deployments" for clarity. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rec card cleanup + usage-aware scoring boost
The native title tooltip takes 2-3 seconds to appear and shows a cursor:help question mark that feels unresponsive. Replaced with a clickable ⓘ icon that toggles the explanation text inline. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
30 published/base pairs show as duplicate entries with split metrics. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove github-source Secret from manifests-infra.yaml.j2 - Remove sourceSecret conditionals from both BuildConfigs - Remove github_token and webhook_secret from .example vars files - Update github_repo to rhpds/rcars in .example files - Remove github_token from deployment docs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Published CIs (Virtual CIs) and their base CIs appeared as separate entries with split metrics — the published got provisions/sales while the base got dev/event cost, making base CIs score as high retirement candidates (65-80) even though they're actively needed. 29 pairs affected. Adds post-merge step that detects pairs via published_ci_name field, combines their metrics under the published entry, and removes the base. Also excludes base CIs from catalog backfill to prevent re-adding with zeros. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevents silent dict overwrites when multiple stage variants of a base CI point to different published CIs. Prefers the prod stage link. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add try/except fallback in call_llm() so LiteMaaS failures fall back to Vertex/Anthropic instead of crashing the request - Cap recommendation scores at 0-100 in usage boost and duration penalty - Add frontend safety clamp in RecCard to prevent >100% display - Add checksum/secrets annotation to pod templates so secret value changes trigger automatic rollouts on --tags apply - Add end-to-end advisor smoke test to Ansible deployer (runs on deploy, apply, and smoke-test tags) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add missing Retirement Analysis section to web guide with full dashboard walkthrough (time windows, prod/without-prod tabs, scoring) - Fix Browse page docs: add Filters panel, v2 badge, infrastructure details, restructure into subsections matching actual UI - Fix Content Analysis docs: filter pills → dropdowns, add search - Fix Admin docs: add all 5 stat cards, Workloads tab, Recent Jobs - Restructure deployment guide: brief architecture recap with link to system-design.md, remove local paths, use plain oc exec pattern, absorb operational workflows from CLI guide - Restructure CLI guide: move env vars to bottom in grouped tables, remove operational workflows (now in deployment), verify all 25 commands against cli.py - Remove content overlap section from operations guide (redundant with architecture doc), remove local worker instructions - Delete development guide (no local dev workflow needed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Smoke test: add -f and --max-time 30 to curl calls so HTTP errors and hangs are caught properly - Checksum annotations: remove oauth_client_secret from API/worker pod checksums since those pods don't consume that secret - Usage boost: add max(0, ...) lower bound for consistency with duration_penalty clamping Skipped: 24-candidate threshold assertion — candidate count depends on catalog size and query, not a fixed deployment contract. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Overlap report was returning pairs from all stages regardless of which stage was selected. Switching between prod/event/dev and recomputing left stale pairs from other stages in the view. - Add stage parameter to get_overlap_report() and get_similarity_stats() - Pass stage filter through the /admin/overlap API endpoint - Frontend passes selected stage when fetching and reloads on stage change Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove developer filesystem paths from WORKLOG.md and strip hardcoded password from alembic.ini default connection string (overridden by env.py at runtime anyway). Closes #20 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Closes #22 - XSS: escape HTML entities before markdown rendering in AdvisorPage.tsx - SQL injection: validate start_date matches ISO format (YYYY-MM-DD) in all _build_*_sql() functions in reporting_sync.py - SSRF: validate URL scheme and reject private/internal IPs in event_parser.py _fetch_html() - URL scheme: restrict clone_showroom() to https:// URLs only in analyzer.py - Pydantic: use HttpUrl type for OverrideUrlRequest in catalog.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Redact secrets and credentials from tracked files
fix: Update link for web guide
Security: Input sanitization — XSS, SSRF, SQL injection
…content Items without a Showroom URL (like Portworx Labs) were invisible to the advisor because they never received embeddings. The scan pipeline required a showroom_url to generate analysis and embeddings, leaving metadata-only catalog items completely unsearchable. This adds a metadata embedding pass to the scan command that generates embeddings from available catalog fields (display_name, description, category, product) for items that have no Showroom URL and no existing embeddings. Changes: - analyzer.py: add build_metadata_embedding_text() to construct embedding text from catalog metadata fields - database.py: add get_items_needing_metadata_embedding() to find catalog items without Showroom URLs that lack embeddings - cli.py: add metadata embedding pass after the main Showroom analysis loop in the scan command, ensuring it runs even when there are no Showroom items to analyze Closes #38 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce a light/dark theme toggle for the RCARS UI. Users who prefer light mode can now switch via a sun/moon button in the header bar. - Create useTheme hook with React context, localStorage persistence, and data-theme attribute on <html> - Convert hardcoded dark colors in lcars.css to CSS custom properties - Add [data-theme="light"] overrides with light-friendly palette - Wire ThemeProvider into App.tsx and add toggle button to LcarsHeader - Update inline styles in header menu to use CSS variables Closes #37 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add light mode theme toggle
Generate embeddings from catalog metadata for items without Showroom …
Revert "Add light mode theme toggle"
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds a light/dark theme system to the RCARS frontend. A new ChangesLight/Dark Theme System
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/frontend/src/components/lcars/LcarsHeader.tsx (1)
158-164: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winConsider adding
aria-labelfor better screen reader support.The theme toggle button currently uses a
titleattribute which provides a tooltip on hover, but adding anaria-labelwould improve accessibility for screen reader users.♿ Suggested accessibility enhancement
<button className="theme-toggle" onClick={toggleTheme} title={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} + aria-label={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} > {theme === 'dark' ? '\u2600' : '\u263D'} </button>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/frontend/src/components/lcars/LcarsHeader.tsx` around lines 158 - 164, The theme toggle button with className="theme-toggle" and onClick={toggleTheme} currently only has a title attribute for accessibility, but lacks an aria-label attribute which is essential for screen reader users. Add an aria-label attribute to the button element that provides the same descriptive text as the existing title attribute, ensuring it clearly indicates the current theme state and what action will occur when clicked by screen reader users.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/frontend/src/components/lcars/LcarsHeader.tsx`:
- Around line 158-164: The theme toggle button with className="theme-toggle" and
onClick={toggleTheme} currently only has a title attribute for accessibility,
but lacks an aria-label attribute which is essential for screen reader users.
Add an aria-label attribute to the button element that provides the same
descriptive text as the existing title attribute, ensuring it clearly indicates
the current theme state and what action will occur when clicked by screen reader
users.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Enterprise
Run ID: 64ca0ae1-56bf-4239-93b9-9d771deaff53
📒 Files selected for processing (4)
src/frontend/src/App.tsxsrc/frontend/src/components/lcars/LcarsHeader.tsxsrc/frontend/src/hooks/useTheme.tssrc/frontend/src/styles/lcars.css
Reverts #43